
#include "gkt_types.h"
#include "gkt_board.h"
#include "gkt_os.h"
#include "g_spi.h"
#include "gkt_debug.h"
#include "gkt_gpio.h"

#define SPI_DEVICE_SPI0	0
#define SPI_DEVICE_SPI1	1
#define SPI_DEVICE_SPI2	2
#define SPI_DEVICE_HSPI	SPI_DEVICE_SPI2
#define SPI_DEVICE_MAX	3

/* slave maxnums per device */
#define SPI_SLAVE_MAXNUMS_PER_DEVICE	8

#if defined(GKT_CONFIG_SPI0_SLAVE_NUMS) && (GKT_CONFIG_SPI0_SLAVE_NUMS > 0)
#if (GKT_CONFIG_SPI0_SLAVE_NUMS > SPI_SLAVE_MAXNUMS_PER_DEVICE)
#error "GKT_CONFIG_SPI0_SLAVE_NUMS should <= SPI_SLAVE_MAXNUMS_PER_DEVICE"
#endif
#define SPI0_SLAVE_NUMS	GKT_CONFIG_SPI0_SLAVE_NUMS
#if !defined(GKT_CONFIG_SPI0_SCK_PAD) || !defined(GKT_CONFIG_SPI0_MOSI_PAD)
#error "should define GKT_CONFIG_SPI0_SCK_PAD, GKT_CONFIG_SPI0_MOSI_PAD and GKT_CONFIG_SPI0_MISO_PAD"
#endif
#else
#define SPI0_SLAVE_NUMS	0
#endif

#if defined(GKT_CONFIG_SPI1_SLAVE_NUMS) && (GKT_CONFIG_SPI1_SLAVE_NUMS > 0)
#if (GKT_CONFIG_SPI1_SLAVE_NUMS > SPI_SLAVE_MAXNUMS_PER_DEVICE)
#error "GKT_CONFIG_SPI1_SLAVE_NUMS should <= SPI_SLAVE_MAXNUMS_PER_DEVICE"
#endif
#define SPI1_SLAVE_NUMS	GKT_CONFIG_SPI1_SLAVE_NUMS
#define SPI0_SLAVE_NUMS	GKT_CONFIG_SPI0_SLAVE_NUMS
#if !defined(GKT_CONFIG_SPI1_SCK_PAD) || !defined(GKT_CONFIG_SPI1_MOSI_PAD) || !defined(GKT_CONFIG_SPI1_MISO_PAD)
#error "should define GKT_CONFIG_SPI1_SCK_PAD, GKT_CONFIG_SPI1_MOSI_PAD and GKT_CONFIG_SPI1_MISO_PAD"
#endif
#else
#define SPI1_SLAVE_NUMS	0
#endif

#if defined(GKT_CONFIG_SPI2_SLAVE_NUMS) && (GKT_CONFIG_SPI2_SLAVE_NUMS > 0)
#if (GKT_CONFIG_SPI2_SLAVE_NUMS > SPI_SLAVE_MAXNUMS_PER_DEVICE)
#error "GKT_CONFIG_SPI2_SLAVE_NUMS should <= SPI_SLAVE_MAXNUMS_PER_DEVICE"
#endif
#define SPI2_SLAVE_NUMS	GKT_CONFIG_SPI2_SLAVE_NUMS
//#define SPI0_SLAVE_NUMS	GKT_CONFIG_SPI0_SLAVE_NUMS
#if !defined(GKT_CONFIG_SPI2_SCK_PAD) || !defined(GKT_CONFIG_SPI2_MOSI_PAD) || !defined(GKT_CONFIG_SPI2_MISO_PAD)
#error "should define GKT_CONFIG_SPI2_SCK_PAD, GKT_CONFIG_SPI2_MOSI_PAD and GKT_CONFIG_SPI2_MISO_PAD"
#endif
#else
#define SPI2_SLAVE_NUMS	0
#endif

#define SPI_SLAVE_TOTAL_NUMS	\
	(SPI0_SLAVE_NUMS + SPI1_SLAVE_NUMS + SPI2_SLAVE_NUMS)

enum {
	SPI_PAD_SCK = 0,
	SPI_PAD_MOSI,
	SPI_PAD_MISO,
	SPI_PAD_MAX
};


/************************************************************
 * slave ncs pads
 *
 * GKT_CONFIG_SPI0_SLAVE0_NCS_PAD
 * GKT_CONFIG_SPI0_SLAVE1_NCS_PAD
 * GKT_CONFIG_SPI1_SLAVE0_NCS_PAD
 ************************************************************/
#define SPI_SLAVE_NCS_PAD_DEFINE(dev_id, slave_id)	\
	GKT_CONFIG_SPI##dev_id##_SLAVE##slave_id##_NCS_PAD

#define SPI_1_SLAVES_NCS_PAD_DEFINE(dev_id)	\
	SPI_SLAVE_NCS_PAD_DEFINE(dev_id, 0)
#define SPI_2_SLAVES_NCS_PAD_DEFINE(dev_id)	\
	SPI_1_SLAVES_NCS_PAD_DEFINE(dev_id),	\
	SPI_SLAVE_NCS_PAD_DEFINE(dev_id, 1)
#define SPI_3_SLAVES_NCS_PAD_DEFINE(dev_id)	\
	SPI_2_SLAVES_NCS_PAD_DEFINE(dev_id),	\
	SPI_SLAVE_NCS_PAD_DEFINE(dev_id, 2)
#define SPI_4_SLAVES_NCS_PAD_DEFINE(dev_id)	\
	SPI_3_SLAVES_NCS_PAD_DEFINE(dev_id),	\
	SPI_SLAVE_NCS_PAD_DEFINE(dev_id, 3)
#define SPI_5_SLAVES_NCS_PAD_DEFINE(dev_id)	\
	SPI_4_SLAVES_NCS_PAD_DEFINE(dev_id),	\
	SPI_SLAVE_NCS_PAD_DEFINE(dev_id, 4)
#define SPI_6_SLAVES_NCS_PAD_DEFINE(dev_id)	\
	SPI_5_SLAVES_NCS_PAD_DEFINE(dev_id),	\
	SPI_SLAVE_NCS_PAD_DEFINE(dev_id, 5)
#define SPI_7_SLAVES_NCS_PAD_DEFINE(dev_id)	\
	SPI_6_SLAVES_NCS_PAD_DEFINE(dev_id),	\
	SPI_SLAVE_NCS_PAD_DEFINE(dev_id, 6)
#define SPI_8_SLAVES_NCS_PAD_DEFINE(dev_id)	\
	SPI_7_SLAVES_NCS_PAD_DEFINE(dev_id),	\
	SPI_SLAVE_NCS_PAD_DEFINE(dev_id, 7)

#define SPI_NUMS_SLAVES_NCS_PADS_DEFINE_L1(dev_id, slave_nums)	\
	SPI_##slave_nums##_SLAVES_NCS_PAD_DEFINE(dev_id)
#define SPI_NUMS_SLAVES_NCS_PADS_DEFINE(dev_id, slave_nums)	\
	SPI_NUMS_SLAVES_NCS_PADS_DEFINE_L1(dev_id, slave_nums)

#define SPI_SLAVES_NCS_PADS_DEFINE_L1(dev_id)	\
	SPI_NUMS_SLAVES_NCS_PADS_DEFINE(dev_id, GKT_CONFIG_SPI##dev_id##_SLAVE_NUMS)
#define SPI_SLAVES_NCS_PADS_DEFINE(dev_id)	\
	SPI_SLAVES_NCS_PADS_DEFINE_L1(dev_id)


/************************************************************
 * spi attr
 ************************************************************/
typedef struct _spi_attr {
	void	*device;	// MSPI0, MSPI1, MHSPI
	uint8_t irq_no;
	uint8_t slave_nums;
	uint8_t slave_base_offset;
	G_GPIO_FUN_TYPEDEF	ncs_func;
} spi_attr_s;

/* state */
enum {
	SPI_SLAVE_ST_UNUSED = 0,
	SPI_SLAVE_ST_OPENED,
	SPI_SLAVE_ST_CONFIGD,
	SPI_SLAVE_ST_START,
	SPI_SLAVE_ST_MAX
};

typedef struct _spi_slave {
	uint8_t	slave_id;
	uint8_t	state;
	uint8_t clock_mode;
	uint8_t	data_bytes;
	uint32_t	max_frequence;
	uint32_t	flags;
} spi_slave_s;

typedef struct _spi_device {
	const spi_attr_s	*c_attr;
	const uint8_t	*c_slaves_ncs_pads;
	spi_slave_s	*slaves;

	gkt_semaphore_t	semaphore;

	uint8_t *tmp_buffer;
	uint32_t	tmp_buffer_size;

	uint8_t	hspi_clk_configed : 1;
	uint8_t	pad_sck_configed : 1;
	uint8_t	pad_mosi_configed : 1;
	uint8_t	pad_miso_configed : 1;

	uint8_t	active_slave_id;
	uint8_t	blocked;
} spi_device_s;

typedef struct _spi {
	int	init_ok;
	gkt_mutex_t	mutex;

	spi_device_s	devices[SPI_DEVICE_MAX];
	spi_slave_s	slaves[SPI_SLAVE_TOTAL_NUMS];
} spi_s;

/* handle, dev_id, slave_id */
#define SPI_MAGIC	0x53504900
#define SPI_MAGIC_MASK	0xFFFFFF00
#define SPI_HANDLE(dev_id, slave_id)	\
	(SPI_MAGIC | (((dev_id) & 0x0f) << 4) | ((slave_id) & 0x0f))
#define SPI_DEV_ID(handle)	(((handle) >> 4) & 0x0f)
#define SPI_SLAVE_ID(handle)	((handle) & 0x0f)

